﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Light.Utility
{
    /// <summary>
    /// UDP帮助类
    /// </summary>
    public class UdpHelper
    {

        private static UdpHelper _instance = null;
        /// <summary>
        /// UdpHelper唯一实例
        /// </summary>
        public static UdpHelper Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UdpHelper();
                }
                return _instance;
            }
        }

        private UdpHelper()
        {
            InitializeLocalIP();
            InitializeThreads();

        }

        private const int Port_BroadCast_HB = 10227;
        private const int Port_BroadCast = 1015;
        private const int Port_Message = 10910;
        private UdpClient client_ReceiveMessage;
        private UdpClient client_ReceiveBroadCast;

        private IPAddress localIP;
        /// <summary>
        /// 初始化本地IP和收发消息的UdpClient
        /// </summary>
        private void InitializeLocalIP()
        {
            IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
            foreach (IPAddress item in localIPs)
            {
                if (item.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    localIP = item; break;
                }
            }
            try
            {
                client_ReceiveMessage = new UdpClient(new IPEndPoint(localIP, Port_Message));
                client_ReceiveBroadCast = new UdpClient(new IPEndPoint(IPAddress.Any, Port_BroadCast));

                uint IOC_IN = 0x80000000;
                uint IOC_VENDOR = 0x18000000;
                uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
                client_ReceiveMessage.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
            }
            catch (Exception ex)
            {
                //throw new Exception("系统已启动!系统即将关闭...");
                MsgBox.Warning("系统已启动,系统即将关闭...");
                //Application.Exit();

            }
        }
        /// <summary>
        /// 初始化线程
        /// </summary>
        private void InitializeThreads()
        {
            //ThreadPool.QueueUserWorkItem(new WaitCallback(broadCastHeartBeat));
            //ThreadPool.QueueUserWorkItem(new WaitCallback(listenHeartBeat));
            //ThreadPool.QueueUserWorkItem(new WaitCallback(receive));

            ThreadPool.QueueUserWorkItem(new WaitCallback(receiveBroadCast));
        }

        #region 3个线程对应的方法




        /// <summary>
        /// 监听端口
        /// </summary>
        private void receive(object sender)
        {
            //绑定消息端口
            while (true)
            {
                try
                {
                    IPEndPoint remoteEP = null;
                    byte[] data = new byte[1024];
                    data = client_ReceiveMessage.Receive(ref remoteEP);

                    if (OnDataReceived != null)
                    {
                        OnDataReceived(data, null);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        /// <summary>
        /// 广播心跳
        /// </summary>
        private void broadCastHeartBeat(object sender)
        {
            try
            {
                UdpClient client_HeartBeat = new UdpClient();
                IPEndPoint broadCastEP = new IPEndPoint(IPAddress.Broadcast, Port_BroadCast_HB);
                while (true)
                {
                    byte[] buffer = Encoding.UTF8.GetBytes("H_B|" + localIP.ToString());
                    client_HeartBeat.Send(buffer, buffer.Length, broadCastEP);
                    Thread.Sleep(3000);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 发送广播消息
        /// </summary>
        /// <param name="msg"></param>
        public void BroadCast(string msg)
        {
            try
            {
                UdpClient client_broadCast = new UdpClient();
                IPEndPoint broadCastEP = new IPEndPoint(IPAddress.Broadcast, Port_BroadCast);
                byte[] buffer = Encoding.UTF8.GetBytes(msg);
                client_broadCast.Send(buffer, buffer.Length, broadCastEP);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void receiveBroadCast(object state)
        {
            try
            {

                while (true)
                {
                    IPEndPoint remoteEP = null;
                    byte[] buffer = new byte[1024];

                    buffer = client_ReceiveBroadCast.Receive(ref remoteEP);
                    string text = Encoding.UTF8.GetString(buffer);
                    if (OnBroadCastReceived != null)
                    {
                        OnBroadCastReceived(text, null);

                    }

                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 监听心跳广播
        /// </summary>
        private void listenHeartBeat(object sender)
        {
            try
            {
                UdpClient listenClient = new UdpClient(new IPEndPoint(IPAddress.Any, Port_BroadCast_HB));
                while (true)
                {

                    IPEndPoint remoteEndPoint = null;
                    byte[] buffer = new byte[1024];

                    buffer = listenClient.Receive(ref remoteEndPoint);
                    //屏蔽自身广播
                    //if (Dns.GetHostAddresses(Dns.GetHostName()).Contains(remoteEndPoint.Address)) { continue; }
                    //解析读到的报文
                    string text = Encoding.UTF8.GetString(buffer);
                    string flag = text.Split('|')[0];
                    //string userid = text.Split('|')[1];
                    //string userip = text.Split('|')[2];
                    if (flag == "H_B")
                    {
                        if (OnHeartBeatListened != null)
                        {
                            OnHeartBeatListened(text, null);
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        #endregion


        /// <summary>
        /// 接收数据事件 
        /// 形参sender=收到的数据，默认类型为System.Byte[],e=null，
        /// 可将其反序列Serializer.Deserialize转化为发送时的数据类型)
        /// </summary>
        public event EventHandler OnDataReceived;

        /// <summary>
        /// 监听到其他主机的心跳事件
        /// 形参sender=心跳字符串,e=null）
        /// </summary>
        public event EventHandler OnHeartBeatListened;

        /// <summary>
        /// 接收到广播消息事件
        /// sender=消息内容，e=null
        /// </summary>
        public event EventHandler OnBroadCastReceived;

        /// <summary>
        /// 发送字节
        /// </summary>
        /// <param name="ips">目标IP</param>
        /// <param name="datas">字节数据</param>
        /// <returns>是否发送成功</returns>
        public bool Send(byte[] datas, params string[] ips)
        {
            try
            {
                foreach (var ip in ips)
                {
                    IPAddress ipAddress = IPAddress.Parse(ip);
                    IPEndPoint targetEP = new IPEndPoint(ipAddress, Port_Message);
                    client_ReceiveMessage.Send(datas, datas.Length, targetEP);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return true;
        }

        /// <summary>
        /// 发送对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">待序列的对象</param>
        /// <param name="ips">目标IP</param>
        /// <returns></returns>
        public bool Send<T>(T obj, params string[] ips)
        {
            try
            {
                foreach (var ip in ips)
                {
                    IPAddress ipAddress = IPAddress.Parse(ip);
                    IPEndPoint targetEP = new IPEndPoint(ipAddress, Port_Message);
                    byte[] datas = Serializer.Serialize<T>(obj);
                    client_ReceiveMessage.Send(datas, datas.Length, targetEP);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return true;
        }

    }
}
